Threads and Processes

A thread is like a mini-process within another process

Threads are a Higher Level Process; The kernel does not know these threads exist

In most systems, the kernel is not involved in context switching of individual threads

Threads

A thread can be seen as a lightweight process within a normal heavyweight process
It will usually serve a specific purpose that helps the main process to manage its tasks

Consider a web browser

Benefits

Concurrent Programming

A single thread would perform all the steps in a calculation in a sequence (usually based on the mathematical order of precedence)
In a multi-threaded (or multi-core) system, this can be split into two types of operation

Processing time is reduced from 9 units to 6 units as the concurrent operations can be done simultaneously
A good compiler will identify concurrent instructions and assign to different CPU cores

Java Threads

Each Java program runs in its own heavyweight process

public class Thread extends Object implements Runnable

The Runnable interface defines a run() method that the programmer must implement

Example

class MyWorker extends Thread {
	public void run() {
		System.out.println("I am a worker thread");
	}
}

public class MyMain {
	public static void main (String[] args) {
		MyWorker runner = new MyWorker();
		runner.start();
		System.out.println("I am the main thread");
	}
}

Threads don't start running until explicitly instructed to
You don't know which string output (main or worker) will happen first, as it depends on thread scheduling (However 99% of the time the worker output will occur first)

The MyWorker class extends the Thread class

Java Thread States

Each thread begins in the new state when its object is allocated memory

Synchronisation Problems

class TwoChar extends Thread {
	private char out1, out2;
	public TwoChar(char first, char second) {
		out1 = first;
		out2 = second;
	}
	public void run() {
		System.out.print(out1);
		System.our.print(out2);
	}
}

This thread object has a constructor that sets two internal character variables
When the thread runs, it will output each character one after the other

If we have a main program like so:

public class ThreadExample {
	public statis void main(String[] args) {
		TwoChar tc1 = new TwoChar('A', 'B');
		TwoChar tc2 = new TwoChar('1', '2');
		tc1.start();
		tc2.start();
	}
}

There will be different results when this is run, depending on the JVM thread scheduler
AB12, A1B2, 12AB, 1A2B, 1AB2, A12B
AB12 will probably appear most often as this is the order they appear in the program code, however there is no guarantee about the execution order of threads

Shared Variables

Suppose there is an object that can be shared by multiple threads

class Something {
	private int num = 0;
	public void increase() {
		num++;
	}
}

This object is passed into the constructor of two threads

Something thing = new Something();
MyThread t1 = new MyThread(thing);
MyThread t2 = new MyThread(thing);

At some point during program execution, both threads access the shared object
thing.increase();
We cannot guarantee that both increases will happen (due to thread scheduling)

Race Conditions

Consider what happens at the register (assembly) level when the increase happens

mov eax, num
inc eax
mov num, eax

Works perfectly fine for most of the time, but occasionally the instructions are executed in a way that causes a problem
If the starting value is 0, we would expect it to be 2 after both threads have executed
However, there is a chance that in the midst of carrying these instructions out to increment num, thread 1 runs out of it's time slice which would cause something like this:

T1 T2 NUM
mov eax, num 0
inc eax 0
mov eax, num 0
inc eax 0
mov num, eax 1
mov num, eax 1
Where num is only incremented once, as T1 moves the same value in the accumulator into num as T2 did, as it was cut off during its first burst

This is known as a race condition and is very hard to debug or even notice it happened
When some area of memory isn't written or updated because it was interrupted at just the wrong time

If the code is particularly for something important and vital, eg. a rocket, you don't want these race conditions as you'd want your code to work as intended 100% of the time
Race conditions involve some (even if just a little) uncertainty

Critical Regions

A race condition could happen whenever a variable is shared between multiple threads

Semaphores

The concept of semaphores (or tokens) comes from single track railways